package com.baor.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baor.dao.EquipmentDao;
import com.baor.dao.Equipment_instructionsDao;
import com.baor.domain.*;
import com.baor.service.EquipmentInstructionService;
import com.baor.util.R;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class EquipmentInstructionServiceImpl implements EquipmentInstructionService {

    @Autowired
    private Equipment_instructionsDao EquipmentInstructionDao;
    @Autowired
    private EquipmentDao EquipmentDao;

    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");

    @Override
    public R getList(Map<String, Object> params) {
        Page page = new Page();
        page.setCurrent(Integer.parseInt(params.get("pageIndex").toString()));
        page.setSize(Integer.parseInt(params.get("pageSize").toString()));

        MPJLambdaWrapper<Equipment_instructions> wrapper = new MPJLambdaWrapper<>(Equipment_instructions.class)
                .select(Equipment_instructions::getId,
                        Equipment_instructions::getEquipmentId,
                        Equipment_instructions::getCommand,
                        Equipment_instructions::getOperationId,
                        Equipment_instructions::getScheduledExecutionTime,
                        Equipment_instructions::getStatus,
                        Equipment_instructions::getOperationTime)
                .select(Equipment::getCode,
                        Equipment::getAddress)
                .eq(Equipment_instructions::getIsDeleted, 0)
                .selectAs(UserVO::getUsername, InstructionsVO::getOperationName)
                .leftJoin(Equipment.class, Equipment::getId, Equipment_instructions::getEquipmentId)
                .leftJoin(UserVO.class, UserVO::getId, Equipment_instructions::getOperationId);

        String code = (String) params.get("code");
        String address = (String) params.get("address");
        String command = (String) params.get("command");
        String startTime = (String) params.get("startTime");
        String endTime = (String) params.get("endTime");

        if (StringUtils.hasText(code)) {
            wrapper.like(Equipment::getCode, code);
        }
        if (StringUtils.hasText(address)) {
            wrapper.like(Equipment::getAddress, address);
        }
        if (StringUtils.hasText(command)) {
            wrapper.like(Equipment_instructions::getCommand, command);
        }
        if (StringUtils.hasText(startTime)) {
            wrapper.ge(Equipment_instructions::getScheduledExecutionTime, startTime);
        }
        if (StringUtils.hasText(endTime)) {
            wrapper.le(Equipment_instructions::getScheduledExecutionTime, endTime);
        }

        // 按预约执行时间倒序排列
        wrapper.orderByDesc(Equipment_instructions::getScheduledExecutionTime);

        Page<InstructionsVO> List = EquipmentInstructionDao.selectJoinPage(page, InstructionsVO.class, wrapper);
        Map map = new HashMap();
        map.put("totalSize", List.getTotal());
        map.put("List", List.getRecords());
        return R.ok(map);
    }

    @Override
    public R add(Map<String, Object> params) {
        try {
            // 获取参数
            String scheduledExecutionTimeStr = params.get("scheduledExecutionTime").toString();
            String applyType = params.get("applyType").toString();
            Integer operationId = (Integer) params.get("operationId");
            List<Integer> instructionIds = (List<Integer>) params.get("instructionIds");

            if (!StringUtils.hasText(scheduledExecutionTimeStr)) {
                return R.er("预约执行时间不能为空");
            }

            // 时间格式验证
            if (!isValidDateTime(scheduledExecutionTimeStr)) {
                return R.er("预约执行时间格式错误，请使用 yyyy-MM-dd HH:mm:ss 格式");
            }

            // 检查预约时间是否早于当前时间
            if (isBeforeCurrentTime(scheduledExecutionTimeStr)) {
                return R.er("预约执行时间不能早于当前时间");
            }

            // 根据应用类型确定设备范围
            List<Integer> equipmentIds = getTargetEquipmentIds(applyType, instructionIds);

            if (equipmentIds.isEmpty()) {
                return R.er("未找到符合条件的设备");
            }

            // 验证设备是否存在
            List<Integer> validEquipmentIds = validateEquipmentIds(equipmentIds);
            if (validEquipmentIds.isEmpty()) {
                return R.er("未找到有效的设备");
            }

            // 为每个设备创建指令
            int successCount = 0;
            String currentTime = getCurrentDateTime();

            for (Integer equipmentId : validEquipmentIds) {
                try {
                    // 在插入前检查并处理原有数据
                    handleExistingInstructions(equipmentId);

                    Equipment_instructions instruction = new Equipment_instructions();
                    instruction.setEquipmentId(equipmentId); // 转换为String
                    instruction.setScheduledExecutionTime(scheduledExecutionTimeStr);
                    instruction.setStatus(0); // 待执行
                    instruction.setOperationId(operationId);
                    instruction.setOperationTime(currentTime);
                    instruction.setCommand("设备重启");
                    int result = EquipmentInstructionDao.insert(instruction);
                    if (result > 0) {
                        successCount++;
                    }
                } catch (Exception e) {
                    System.out.println("创建设备指令失败，设备ID: " + equipmentId + ", 错误: " + e.getMessage());
                }
            }

            if (successCount > 0) {
                return R.ok("成功为 " + successCount + " 台设备创建指令");
            } else {
                return R.er("指令创建失败，请稍后重试");
            }

        } catch (Exception e) {
            System.out.println("创建设备指令异常: " + e.getMessage());
            e.printStackTrace();
            return R.er("系统错误，请稍后重试");
        }
    }

    @Override
    public R restart(Integer  id , Integer operationId) {
        System.out.println("当前操作的机器"+ id);
        System.out.println("当前操作者"+ operationId);
        // 在插入前检查并处理原有数据
        handleExistingInstructions(id);

        Equipment_instructions instruction = new Equipment_instructions();
        instruction.setEquipmentId(id); // 转换为String
        instruction.setScheduledExecutionTime(getCurrentDateTime());
        instruction.setStatus(0); // 已执行
        instruction.setOperationId(operationId);
        instruction.setOperationTime(getCurrentDateTime());
        instruction.setCommand("设备重启");
        int result = EquipmentInstructionDao.insert(instruction);
        if (result > 0) {
            Equipment equipment = new Equipment();
            equipment.setIsStatus(1);
            EquipmentDao.update(equipment, new QueryWrapper<Equipment>().eq("id", id));
            return R.ok("重启成功");
        } else {
            return R.er("重启失败");
        }
    }

    /**
     * 验证日期时间格式
     */
    private boolean isValidDateTime(String dateTimeStr) {
        try {
            dateFormat.parse(dateTimeStr);
            return true;
        } catch (ParseException e) {
            return false;
        }
    }

    /**
     * 检查时间是否早于当前时间
     */
    private boolean isBeforeCurrentTime(String dateTimeStr) {
        try {
            Date scheduledTime = dateFormat.parse(dateTimeStr);
            Date currentTime = new Date();
            return scheduledTime.before(currentTime);
        } catch (ParseException e) {
            return true; // 如果解析失败，认为时间无效
        }
    }

    /**
     * 获取当前时间字符串
     */
    private String getCurrentDateTime() {
        return dateFormat.format(new Date());
    }

    private void handleExistingInstructions(Integer equipmentId) {
        try {
            // 创建更新条件
            LambdaUpdateWrapper<Equipment_instructions> updateWrapper = new LambdaUpdateWrapper<>();
            updateWrapper.eq(Equipment_instructions::getEquipmentId, equipmentId.toString())
                    .eq(Equipment_instructions::getStatus, 0)
                    .eq(Equipment_instructions::getIsDeleted, 0);
            // 执行软删除
            Equipment_instructions updateEntity = new Equipment_instructions();
            updateEntity.setIsDeleted(1);
            updateEntity.setUpdatedAt(getCurrentDateTime());

            EquipmentInstructionDao.update(updateEntity, updateWrapper);

        } catch (Exception e) {
            System.out.println("处理设备原有指令失败，设备ID: " + equipmentId + ", 错误: " + e.getMessage());
            throw e;
        }
    }

    /**
     * 根据应用类型获取目标设备ID列表
     */
    private List<Integer> getTargetEquipmentIds(String applyType, List<Integer> instructionIds) {
        List<Integer> equipmentIds = new ArrayList<>();

        try {
            if ("0".equals(applyType)) {
                // 全部设备
                List<Equipment> allEquipments = EquipmentInstructionDao.selectAllEquipment();
                equipmentIds = allEquipments.stream()
                        .map(Equipment::getId)
                        .collect(Collectors.toList());
                System.out.println("全部设备数量: " + equipmentIds.size());

            } else if ("1".equals(applyType)) {
                // 应用部分设备
                if (instructionIds != null && !instructionIds.isEmpty()) {
                    equipmentIds = new ArrayList<>(instructionIds);
                    System.out.println("应用部分设备数量: " + equipmentIds.size());
                } else {
                    throw new IllegalArgumentException("应用部分设备模式需要传入设备ID");
                }

            } else if ("2".equals(applyType)) {
                // 屏蔽部分设备
                List<Equipment> allEquipments = EquipmentInstructionDao.selectAllEquipment();
                // 创建排除设备ID集合
                Set<Integer> excludeIds = instructionIds != null ? new HashSet<>(instructionIds) : new HashSet<>();
                System.out.println("排除设备数量: " + excludeIds.size());
                equipmentIds = allEquipments.stream()//开启流
                        .map(Equipment::getId)//获取设备ID
                        .filter(id -> !excludeIds.contains(id))//过滤掉排除的ID
                        .collect(Collectors.toList()); //转换成列表
                System.out.println("屏蔽后设备数量: " + equipmentIds.size());

            } else {
                throw new IllegalArgumentException("不支持的应用类型: " + applyType);
            }
        } catch (Exception e) {
            System.out.println("设备选择错误: " + e.getMessage());
        }

        return equipmentIds;
    }

    /**
     * 验证设备ID是否存在
     */
    private List<Integer> validateEquipmentIds(List<Integer> equipmentIds) {
        List<Integer> validIds = new ArrayList<>();
        for (Integer id : equipmentIds) {
            try {
                Equipment equipment = EquipmentInstructionDao.selectById(id);
                if (equipment != null && equipment.getIsDeleted() == 0) {
                    validIds.add(id);
                } else {
                    System.out.println("警告：设备ID " + id + " 不存在或已被删除");
                }
            } catch (Exception e) {
                System.out.println("验证设备ID " + id + " 时出错: " + e.getMessage());
            }
        }
        return validIds;
    }

    @Scheduled(fixedDelay = 600000)//
    @Transactional
    public void updateExpiredInstructions() {
        try {
            String currentTime = getCurrentDateTime();
            System.out.println("开始检查过期指令，当前时间: " + currentTime);

            int updatedCount = EquipmentInstructionDao.updateExpiredInstructions(currentTime);

            if (updatedCount > 0) {
                System.out.println("成功更新 " + updatedCount + " 条过期指令状态");
            }
        } catch (Exception e) {
            System.out.println("更新过期指令状态失败: " + e.getMessage());
            e.printStackTrace();
        }
    }
}